package chances.wechat.service;

import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import chances.epg.commons.utils.JSONUtils;
import chances.epg.commons.utils.PathUtils;
import chances.epg.entity.user.WechatUser;
import chances.epg.user.controller.UserResultResponse;
import chances.wechat.config.WeChatMvcConfig;
import chances.wechat.model.WechatToken;
import okhttp3.Call;
import okhttp3.FormBody;
import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

@Service
public class GatewayService {
	
	@Autowired
	WeChatMvcConfig weChatMvcConfig;
	
	private WechatToken wechatToken;
	
	private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
	
	public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
	
	Logger appletlogger = LoggerFactory.getLogger("appletLogger");
	

	@PostConstruct
	public WechatToken getToken(){
		
		if(this.wechatToken == null||!this.wechatToken.isEffective()){
			Thread thread = new Thread(new Runnable() {
				@Override
				public void run() {
					refreshToken();
				}
			});
			thread.start();
		}
		
		return this.wechatToken;
	}
	
	@Scheduled(fixedDelay = 5*60*1000)
	public void refreshToken(){
		try{
		StringBuffer url = new StringBuffer(PathUtils.join(weChatMvcConfig.getWgHost(), "/wechat/token"));
		url.append("?app_code=").append(weChatMvcConfig.getAppCode());
		RestTemplate restTemplate = new RestTemplate();
		WechatToken result = restTemplate.getForObject(url.toString(), 
				WechatToken.class);
		
		this.wechatToken = result;
		}catch(Throwable e){
			e.printStackTrace();
		}
	}
	
	
	public WechatUser login(String code, String state, String type) throws IOException{
		Map<String,String> map = new HashMap<String,String>();
		map.put("code", code);
		map.put("state", state);
		map.put("type", type);
		map.put("app_code", weChatMvcConfig.getAppCode());
		return this.post(WechatUser.class, "/wechat/snslogin", map);
	}
	
	public void proxy(HttpServletRequest request,HttpServletResponse httpResponse,String path) throws IOException{
		Enumeration<String> names = request.getParameterNames();
		Map<String,String> strMap = new HashMap<String,String>();
		for(;names.hasMoreElements();){
			String name = names.nextElement();
			strMap.put(name, request.getParameter(name));
		}
		
		this.proxy(request, httpResponse, path, strMap);
	}
	
	public void proxyMultipart(HttpServletRequest request,HttpServletResponse httpResponse,String path) throws IOException{
		Enumeration<String> names = request.getParameterNames();
		Map<String,String> strMap = new HashMap<String,String>();
		for(;names.hasMoreElements();){
			String name = names.nextElement();
			strMap.put(name, request.getParameter(name));
		}
		
		this.proxyMultipart(request, httpResponse, path, strMap);
	}

	public void proxy(HttpServletRequest request,HttpServletResponse httpResponse,String path,Map<String,String> map) throws IOException{
		String url = PathUtils.join(weChatMvcConfig.getWgHost(),path);
		OkHttpClient okHttpClient = new OkHttpClient()
				.newBuilder().connectTimeout(weChatMvcConfig.getConnectTimeOut(), TimeUnit.SECONDS)
				.readTimeout(weChatMvcConfig.getReadTimeOut(), TimeUnit.SECONDS)
	            .build();
		FormBody.Builder builder = new FormBody.Builder();
		
		for (Entry<String,String> entry : map.entrySet()) {
			builder.add(entry.getKey(), entry.getValue());
		}
		
		RequestBody requestBody = builder.build();
		Request clientRequest = new Request.Builder().url(url).post(requestBody).build();
		
		
		Call call = okHttpClient.newCall(clientRequest);
		
		Response resp = call.execute();
		String content = resp.body().string();
		if(resp.isSuccessful()){
			if(url.indexOf("/qr/scanUpdate") != -1){
				return;
			}
			MediaType type = resp.body().contentType();
			httpResponse.setContentType(type.toString());
			httpResponse.getWriter().append(content);
		}else{
			MediaType type = MediaType.parse("application/json");
			UserResultResponse<String> userResultResponse = new UserResultResponse<String>(content);
			userResultResponse.setCode(500);
			httpResponse.getWriter().write(JSONUtils.fromObject(userResultResponse));
		}
	}
	
	public void proxyMultipart(HttpServletRequest request,HttpServletResponse httpResponse,String path,Map<String,String> map) throws IOException{
		String url = PathUtils.join(weChatMvcConfig.getWgHost(),path);
		OkHttpClient okHttpClient = new OkHttpClient()
				.newBuilder().connectTimeout(weChatMvcConfig.getConnectTimeOut(), TimeUnit.SECONDS)
				.readTimeout(weChatMvcConfig.getReadTimeOut(), TimeUnit.SECONDS)
	            .build();
		
		MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
		if(request instanceof MultipartHttpServletRequest){
			MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
			Iterator<String> iter = multiRequest.getFileNames();
			while (iter.hasNext()) {
				MultipartFile file = multiRequest.getFile(iter.next());
				String disposition = "form-data; name=\""+file.getName()+"\"; filename=\""+file.getOriginalFilename()+"\"";
				builder.addPart(
						Headers.of("Content-Disposition", disposition),
						RequestBody.create(MEDIA_TYPE_PNG, file.getBytes()));
			}
		}
		for (Entry<String,String> entry : map.entrySet()) {
			builder.addFormDataPart(entry.getKey(), entry.getValue());
		}
		
		RequestBody requestBody = builder.build();
		Request clientRequest = new Request.Builder().url(url).post(requestBody).build();
		
		
		Call call = okHttpClient.newCall(clientRequest);
		
		Response resp = call.execute();
		String content = resp.body().string();
		if(resp.isSuccessful()){
			//MediaType type = resp.body().contentType();
			//httpResponse.setContentType(type.toString());
			httpResponse.getWriter().append(content);
		}else{
			UserResultResponse<String> userResultResponse = new UserResultResponse<String>(content);
			userResultResponse.setCode(500);
			httpResponse.getWriter().write(JSONUtils.fromObject(userResultResponse));
		}
	}
	
	public <T> T post(Class<T> type, String path,Map<String,String> map) throws IOException{
		
		String url = PathUtils.join(weChatMvcConfig.getWgHost(),path);
		OkHttpClient okHttpClient = new OkHttpClient()
				.newBuilder().connectTimeout(weChatMvcConfig.getConnectTimeOut(), TimeUnit.SECONDS)
				.readTimeout(weChatMvcConfig.getReadTimeOut(), TimeUnit.SECONDS)
	            .build();
		FormBody.Builder builder = new FormBody.Builder();
		
		for (Entry<String,String> entry : map.entrySet()) {
			builder.add(entry.getKey(), entry.getValue());
		}
		
		RequestBody requestBody = builder.build();
		Request clientRequest = new Request.Builder().url(url).post(requestBody).build();
		Call call = okHttpClient.newCall(clientRequest);
				
		Response resp = call.execute();
		
		String content = resp.body().string();	
		return JSONUtils.toObject(content, type);
		
	}
	
	public Map program(Map<String,String> map) throws IOException{
		
		return this.post(Map.class, "/play/program", map);
	}
	
	

	public String getAppCode() {
		return weChatMvcConfig.getAppCode();
	}
	
	public String postJson(HttpServletRequest request,HttpServletResponse httpResponse,String path,WechatUser user) {
		String url = PathUtils.join(weChatMvcConfig.getWgHost(),path);
		url = url + "?"+request.getQueryString();
		
        OkHttpClient okHttpClient = new OkHttpClient().newBuilder()
                .connectTimeout(weChatMvcConfig.getConnectTimeOut(), TimeUnit.SECONDS)
                .readTimeout(weChatMvcConfig.getReadTimeOut(), TimeUnit.SECONDS).build();

        RequestBody body = RequestBody.create(JSON, JSONUtils.fromObject(user));
        
        
        Request clientRequest = new Request.Builder().url(url).post(body).build();

        Call call = okHttpClient.newCall(clientRequest);
        Response resp;
        appletlogger.info("post url:{}\r\n json:{}", url, JSONUtils.fromObject(user));
        try {
            resp = call.execute();
            String result = resp.body().string();
            appletlogger.info("result:{}", result);
            return result;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }

    }

}
